/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import java.util.regex.Matcher;

import junit.framework.Assert;
import junit.framework.TestCase;

import org.junit.Test;





/**
 * Performs Validation Test for url validations.
 *
 * @version $Revision: 1128446 $ $Date: 2011-05-27 13:29:27 -0700 (Fri, 27 May 2011) $
 */
public class UrlValidatorTest extends TestCase {

   private boolean printStatus = false;
   private boolean printIndex = false;//print index that indicates current scheme,host,port,path, query test were using.

   public UrlValidatorTest(String testName) {
      super(testName);
   }

   
   @Test
   public void testManualTest()
   {
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   
	   //check first section -- true
	   System.out.println("Checking first section");
	   System.out.println(urlVal.isValid("http://www.amazon.com") + " true");
	   System.out.println(urlVal.isValid("https://www.amazon.com") + " true");//since these are true, will only check true again if testing more sections
	   
	   //check first section -- false
	   System.out.println(urlVal.isValid("httpq://www.amazon.com") + " true");//test for extra character
	   System.out.println(urlVal.isValid("ht://www.amazon.com")+ " true"); // test for fewer characters
	   System.out.println(urlVal.isValid("http,://www.amazon.com")+ " false");//test for char that doesn't belong

	   //check second section -- false
	   System.out.println("Checking second section");
	   System.out.println(urlVal.isValid("http://ww.amazon.com")+ " false"); //test for fewer chars
	   System.out.println(urlVal.isValid("http://ww;.amazon.com")+ " false"); //test for char that doesn't belong

	   //check third section -- false
	   System.out.println("Checking third section");
	   System.out.println(urlVal.isValid("http://www.am*,zon.com")+ " false");//check for chars that don't belong
	   
	   //check fourth section
	   System.out.println("Checking fourth section");
	   System.out.println(urlVal.isValid("http://www.amazon.zac")+ " false"); // test for random word instead of recognized extension
	   System.out.println(urlVal.isValid("http://www.amazon.comx")+ " false"); // test for additional char after recognized extension
	   System.out.println(urlVal.isValid("http://www.amazon.com,")+ " false");// test for char that doesn't belong in URL

	   //check fifth section
	   System.out.println("Checking fifth section");
	   System.out.println(urlVal.isValid("http://www.amazon.com/deals")+ " true"); //test if can add and verify correct fifth section
	   System.out.println(urlVal.isValid("http://www.amazon.com/deals,")+ " false"); //test if will deny if this section contains extra chars

	   //
	   
   }
   
   //is this just using asserts instead of prints like above?
   @Test 
   public void testYourFirstPartition()
   {
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	  //  Protocol (ie. http:, ftp:,https:), according to URLValidator.
	   String [] schemeArrayGood = {"http://", "ftp://", "https://"}; //3 good, 3 bad
	   String [] schemeArrayBad = {"://", "http..:", "http" }; 
	   int totalCount = schemeArrayGood.length + schemeArrayBad.length;
	   String[][] urlArray = new String[totalCount][2];//we are going to have 5 entries, and put true or false with each of them

	   //set up each scheme with "true" or "false" depending on if it comes from bad or good arrays
	   for(int x = 0; x<totalCount; x++){
		   if( x < schemeArrayGood.length){
			   urlArray[x][0]= schemeArrayGood[x];
			   urlArray[x][1] = "true";
		   }
		   else{
			   urlArray[x][0]= schemeArrayBad[x-schemeArrayGood.length];
			   urlArray[x][1] = "false"; 
		   }
	   }
	   
	   //test each against their values we gave
	   for (int x = 0; x< totalCount; x++){
		   //isValid expects two objects, not a boolean. So we cast to object and it works
		    if( !(urlVal.isValid(urlArray[x][0] + "www.amazon.com") ==  Boolean.valueOf(urlArray[x][1]) ) ){
		    	System.out.println("Failed at: " + urlArray[x][0] + " " + urlArray [x][1]); 
		    }
		    assertEquals(urlVal.isValid(urlArray[x][0] + "www.amazon.com") , (Object) Boolean.valueOf(urlArray[x][1]) );

	   }

   }
   @Test
   public void testYourSecondPartition(){
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	  //  Protocol (ie. http:, ftp:,https:), according to URLValidator.
	   String [] hostArrayGood = {"www.amazon.com", "255.255.255.255", "drive.google.com", "0.0.0.0"}; //3 good, 2 bad
	   String [] hostArrayBad = {"www.amazon,com", "256.256.256.3000","-1.-1.-1.-1" }; //3 good, 2 bad
	   int totalCount = hostArrayGood.length + hostArrayBad.length;
	   String[][] urlArray = new String[totalCount][2];//we are going to have 5 entries, and put true or false with each of them

	   //set up each scheme with "true" or "false" depending on if it comes from bad or good arrays
	   for(int x = 0; x<totalCount; x++){
		   if( x < hostArrayGood.length){
			   urlArray[x][0]= hostArrayGood[x];
			   urlArray[x][1] = "true";
		   }
		   else{
			   urlArray[x][0]= hostArrayBad[x-hostArrayGood.length];
			   urlArray[x][1] = "false"; 
		   }
	   }
	   
	   //test each against their values we gave
	   for (int x = 0; x< totalCount; x++){
		   //isValid expects two objects, not a boolean. So we cast to object and it works
		    if( !(urlVal.isValid("http://" + urlArray[x][0]) ==  Boolean.valueOf(urlArray[x][1]) ) ){
		    	System.out.println("Failed at: " + urlArray[x][0] + " " + urlArray [x][1]); 
		    }
		    assertEquals(urlVal.isValid("http://" + urlArray[x][0] ) , (Object) Boolean.valueOf(urlArray[x][1]) );
	   }
   }
   
   @Test
   public void testIsValid()
   {
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   //scheme,host,port,path, query 
	   String [] schemeArrayGood = {"http://", "ftp://", "https://"}; //3 good, 2 bad
	   String [] schemeArrayBad = {"://", "http,://" }; 
	   int totalScheme = schemeArrayGood.length + schemeArrayBad.length;
	   
	   String [] hostArrayGood = {"www.amazon.com", "255.255.255.255", "drive.google.com", "0.0.0.0"}; //3 good, 2 bad
	   String [] hostArrayBad = {"www.amazon,com", "256.256.256.256","-1.-1.-1.-1" }; //3 good, 2 bad
	   int totalHost = hostArrayGood.length + hostArrayBad.length;

	   String [] portArrayGood = {":80", ":65535", ":0" , ""}; //4 good, 2 bad
	   String [] portArrayBad = {":-1", ":65536", ":,65535" }; 
	   int totalPort = portArrayGood.length + portArrayBad.length;
	   
	   String [] pathArrayGood = {"/abc", "/3298", "/234abc" , ""}; //4 good, 2 bad
	   String [] pathArrayBad = {"/..", "//abc", "/,abc" }; 
	   int totalPath = pathArrayGood.length + pathArrayBad.length;
	   
	   
	   //The query component is indicated by the first question
	   //mark ("?") character and terminated by a number sign ("#") character
	   //or by the end of the URI.
	   //TESTING NOTE: we are going to prepend # on the url in frag section, since it is only present if frag is present
	   String [] queryArrayGood = {"?name=abc", "?name=3298", "?name=234abc" , "?XXXXXXXXXXXXXXX"}; //4 good, 2 bad
	   String [] queryArrayBad = {"`π", "XXXXXXXXXXXXXXXπ", "\\\\\\\\", "}", "...." };
	   int totalQuery = queryArrayGood.length + queryArrayBad.length;

	   
	   String [] fragmentArrayGood = {"#name=abc", "#name=3298", "#name=234abc" , ""}; //4 good, 2 bad
	   //String [] fragmentArrayBad = {"."}; 
	   String [] fragmentArrayBad = {}; 

	   int totalFragment = fragmentArrayGood.length + fragmentArrayBad.length;
	   
	   
	   int totalURLCount = totalHost * totalScheme * totalPort * totalPath * totalQuery;
	   
	   
	   //String[][] urlArray = new String[totalURLCount][2];//we are going to have totalURLCount entries, and put true or false with each of them
	   String testURL = "";
	   Boolean queryPresense = false;
	   Boolean urlTest = true;
	   int totalCounter = 0;
	   int failedCounter = 0;
	   for (int x = 0; x<totalScheme; x++){
		   for(int y = 0; y<totalHost; y++){
			   for( int z = 0; z< totalPort; z++){
				   for(int a = 0; a < totalPath; a++){
					   for(int b = 0; b< totalQuery; b++){
						   for (int c = 0; c< totalFragment;c++){
							   //add scheme section of URL
							   if( x < schemeArrayGood.length){
								   testURL += schemeArrayGood[x];
							   }
							   else{
								   testURL += schemeArrayBad[x-schemeArrayGood.length];
								   urlTest = false; 
							   }
							   
							   //add host section of URL
							   if( y < hostArrayGood.length){
								   testURL += hostArrayGood[y];
							   }
							   else{
								   testURL += hostArrayBad[y-hostArrayGood.length];
								   urlTest = false; 
							   }
							   
							   //add port section of URL
							   if( z < portArrayGood.length){
								   testURL += portArrayGood[z];
							   }
							   else{
								   testURL += portArrayBad[z-portArrayGood.length];
								   urlTest = false; 
							   }
							   
							   //add path section of URL
							   if( a < pathArrayGood.length){
								   testURL += pathArrayGood[a];
							   }
							   else{
								   testURL += pathArrayBad[a-pathArrayGood.length];
								   urlTest = false; 
							   }
							   
							   //add query section of URL
							   if( b < queryArrayGood.length){
								   testURL += queryArrayGood[b];
							   }
							   else{
								   testURL += queryArrayBad[b-queryArrayGood.length];
								   urlTest = false; 
							   }
							   
							   //add fragment section of URL, only if query is present
							   if( c < fragmentArrayGood.length){
								   testURL += fragmentArrayGood[c];
							   }
							   else{
								   testURL += fragmentArrayBad[c-fragmentArrayGood.length];
								   urlTest = false; 
							   }
							   
							   //we should now have a complete URL, and a bool to see if it is valid or not
							   //commented out to show errors
							    //assertEquals(urlVal.isValid(testURL) , (Object) urlTest );
							    if( !(urlVal.isValid(testURL) ==  urlTest) ) {
							    	System.out.println("Failed at: " + testURL); 
							    	System.out.println("Is " + String.valueOf(urlTest) + " but tested as " + String.valueOf(urlVal.isValid(testURL))); 
							    	System.out.println("-----------" + totalCounter + "------------"); 
							    	failedCounter ++;
							    }
							    //assertEquals(urlVal.isValid(testURL) ,   (Object) Boolean.valueOf(urlTest));
							    
							   totalCounter ++;
							   
							   testURL = "";
							   urlTest = true;
						   }
					   }
				   }
			   }
		   }
		   
	   }
   	System.out.println("Total URL's tested: " + String.valueOf(totalCounter)); 
   	System.out.println("Failed: " + String.valueOf(failedCounter)); 

	   
   }
   
   @Test
   /**
    * Tests focused on URL queries and fragments
    */
   public void testAnyOtherUnitTest()
   {
	   
	   UrlValidator urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);
	   String testURL="https://www.amazon.com/deals", query=null, frag=null;

	   query = null;
	   testURL += "?" + query;
	   System.out.println("isValidQuery(): '" + query + "'=" + urlVal.isValidQuery(query) );
	   query = "good=query";
	   testURL += "?" + query;
	   System.out.println("isValidQuery(): '" + query + "'=" + urlVal.isValidQuery(query) );
	   query = "badquery";
	   testURL += "?" + query;
	   System.out.println("isValidQuery(): '" + query + "'=" + urlVal.isValidQuery(query) );
	   
	   frag = null;
	   testURL += "?" + frag;
	   System.out.println("isValidFragment(): '" + frag + "'=" + urlVal.isValidFragment(frag) );
	   frag = "goodfrag";
	   testURL += "?" + frag;
	   System.out.println("isValidFragment(): '" + frag + "'=" + urlVal.isValidFragment(frag) );
	   frag = "badfrag{}";
	   testURL += "?" + frag;
	   System.out.println("isValidFragment(): '" + frag + "'=" + urlVal.isValidFragment(frag) );
	   
	   urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES+UrlValidator.NO_FRAGMENTS);
	   frag = null;
	   testURL += "?" + frag;
	   System.out.println("isValidFragment(): '" + frag + "'=" + urlVal.isValidFragment(frag) );
	   frag = "goodfrag";
	   testURL += "?" + frag;
	   System.out.println("isValidFragment(): '" + frag + "'=" + urlVal.isValidFragment(frag) );
	   frag = "badfrag{}";
	   testURL += "?" + frag;
	   System.out.println("isValidFragment(): '" + frag + "'=" + urlVal.isValidFragment(frag) );

	   
	   
	   /* NOTE: checkParse() method added to UrlValidator
	   	 * 	--provides breakdown of URL components.
	   	 *  --provides diagnostics: isValid() for URL query and fragment vs. regex pattern match
	  	 	e.g. of test output
				----------------------------------------------------------
				https://www.amazon.com/deals?name=abc#goodfrag failed
				----------------------------------------------------------
				scheme	https
				auth	www.amazon.com
				path	/deals
				query	name=abc
				frag	goodfrag
				
				query	'name=abc'
					isValidQuery() false
					regex pattern match true
				
				fragment	'goodfrag'
					isValidFragment() true
					No regex pattern match.  isOff(NO_FRAGMENTS)=true
		*/

	   urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);

	   // case1 good scheme/auth/path; no query; no fragment
	   testURL = "https://www.amazon.com/deals";
	   urlVal.checkParse(testURL);	

	   // case2 good scheme/auth/path; good query; no fragment
	   testURL = "https://www.amazon.com/deals?name=abc";
	   urlVal.checkParse(testURL);	
	   
	   // case3 good scheme/auth/path; bad query; no fragment
	   testURL = "https://www.amazon.com/deals?badquery";
	   urlVal.checkParse(testURL);	


	   // case4 good scheme/auth/path; no query; good fragment
	   testURL = "https://www.amazon.com/deals#goodfrag";
	   urlVal.checkParse(testURL);	

	   // case5 good scheme/auth/path; no query; bad fragment
	   testURL = "https://www.amazon.com/deals#badfrag{}";
	   urlVal.checkParse(testURL);	

	   urlVal = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES+UrlValidator.NO_FRAGMENTS);
	   // case6 good scheme/auth/path; no query; good fragment + turn on NO_FRAGMENTS
	   testURL = "https://www.amazon.com/deals#goodfrag";
	   urlVal.checkParse(testURL);	
	   
	   // case7 good scheme/auth/path; no query; bad fragment + turn on NO_FRAGMENTS
	   testURL = "https://www.amazon.com/deals#badfrag{}";
	   urlVal.checkParse(testURL);	
   
   }

}

